package task;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import com.google.gson.Gson;

import config.TaskConfig;

import output.AbstractOutputer;
import output.OutputSQLite;

public class TaskControllor {
	// read from config.properties	
	
	private static final String TASK_RUNNING_TIME = "taskRunningTime";
	private static final String MEASURE_STRATEGY = "measureStrategy";
	
	private static final String TASK_RUNNER_HEAD = "task.TaskRunner";
	private static final String TASK_HEAD = "task.Task";
	private static final String DB_FILE = "database";
	
	
	private AbstractTaskRunner taskRunner;
	
	private List<AbstractTask> tasks = new ArrayList<AbstractTask>();
	
	/**
	 * Initialize the Task Runner according to the "config.properties" file.
	 */
	public void initTaskRunner(File configFile) {
		Properties prop = new Properties();
		try {
			prop.load(new FileInputStream(configFile));
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		int taskRunningTime = Integer.parseInt(prop.getProperty(TASK_RUNNING_TIME));
		
		String measureStrategy = this.formatConfigValue(prop.getProperty(MEASURE_STRATEGY));

		System.out.println("db:" + prop.getProperty(DB_FILE));
		OutputSQLite.getInstance().init(new File(prop.getProperty(DB_FILE)));

		
		try {
			Class classTaskRunner = Class.forName(TASK_RUNNER_HEAD + measureStrategy);
			this.taskRunner = (AbstractTaskRunner) classTaskRunner.newInstance();
			this.taskRunner.setRunningTime(taskRunningTime);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
	
	public void initTasks(File configDir) {
		for(File f : configDir.listFiles()) {
			if(f.isDirectory()) {
				this.initTasks(f);
			} else if(f.getName().endsWith(".json")) {
				try {
					Gson gson = new Gson();
					BufferedReader br;
					br = new BufferedReader(new FileReader(f));
					TaskConfig[] tcs = gson.fromJson(br, TaskConfig[].class);
					for(TaskConfig tc : tcs) {
						this.tasks.addAll(createTask(tc));
					}
				} catch (FileNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}
		}
	}
	
	private List<AbstractTask> createTask(TaskConfig config) {
		List<AbstractTask> ts = new ArrayList<AbstractTask>();
		try {
			Class classTask = Class.forName(TASK_HEAD + 
					formatConfigValue(config.workingsetType) + 
					formatConfigValue(config.elementType) + 
					formatConfigValue(config.behavior));
			
			for(int stride = config.strideScale.min; 
					stride <= config.strideScale.max; 
					stride += config.strideScale.step) {
				for(int workingsetSize = config.workingsetSizeScale.min; 
						workingsetSize <= config.workingsetSizeScale.max; 
						workingsetSize += config.workingsetSizeScale.step) {
					for(int threadNum = config.threadNumScale.min; 
							threadNum <= config.threadNumScale.max; 
							threadNum += config.threadNumScale.step) {
						AbstractTask t = (AbstractTask) classTask.newInstance();
						t.setStride(stride);
						t.setWorkingsetSize(workingsetSize);
						t.setThreadNum(threadNum);
						ts.add(t);
					}
				}
			}
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return ts;
	}
	
	
	public void run() {
		System.out.println("I have " + tasks.size() + " tasks to run.");
		for(AbstractTask t : this.tasks) {
			this.taskRunner.setTask(t);
			this.taskRunner.runTask();
			OutputSQLite.getInstance().outputTaskResult(taskRunner);
		}
		OutputSQLite.getInstance().cleanup();
		System.out.println("Done.");
	}
		
	private String formatConfigValue(String value) {
		value = value.replaceAll("\\s", "");
		return value.substring(0, 1).toUpperCase() + value.substring(1).toLowerCase();
	}
	
	
	public void showMeSomething() {
		System.out.println("I have " + tasks.size() + " tasks.");
	}
	
	
//	private TaskBase[] tasks;
//	
//	public TaskBase createTask(String taskType) {
//		// create task base on config
//		return null;
//	}
//	
//	public WorkingsetBase createWorkingset(String wsType, String eType) {
//		// create workingset base on config
//		return null;
//	}
//	
//	public IOutputer createTaskResultOutputer(String outputType) {
//		// create output base on config
//		return null;
//	}
//	
//	public void run(String configPath) {
//		
//	}
	// store result
}
